/*
 * @Author: cyfqyb
 * @Date: 2023-10-16 10:35:41
 * @LastEditors: cyfqyb cy15770703229@163.com
 * @LastEditTime: 2023-10-22 22:42:13
 * @FilePath: \ImBackend\test\test.ts
 * @Description: 介绍
 */
class MyPromise {
  constructor(
    executor: (
      resolve: (value?: any) => void,
      reject: (reason?: any) => void
    ) => void
  ) {
    this.initValue();
    this.initBind();
    try {
      executor(this.resolve, this.reject);
    } catch (e) {
      this.reject(e);
    }
  }
  PromiseResult!: any;
  PromiseStatus!: "pending" | "fulfilled" | "rejected";
  onFulfilledCallbacks: Array<any> = [];
  onRejectedCallbacks: Array<any> = [];
  thenPromise!: MyPromise;
  initValue() {
    this.PromiseResult = null;
    this.PromiseStatus = "pending";
  }

  initBind() {
    //初始化this
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);
  }
  resolve(value: any) {
    if (this.PromiseStatus !== "pending") return;
    this.PromiseStatus = "fulfilled";
    this.PromiseResult = value;
    while (this.onFulfilledCallbacks.length) {
      this.onFulfilledCallbacks.shift()(this.PromiseResult);
    }
  }
  reject(reason: any) {
    if (this.PromiseStatus !== "pending") return;
    this.PromiseStatus = "rejected";
    this.PromiseResult = reason;
    while (this.onRejectedCallbacks.length) {
      this.onRejectedCallbacks.shift()(this.PromiseResult);
    }
  }
  then(onFulfilled?: (value: any) => any, onRejected?: (reason: any) => any) {
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (value: any) => value;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason: any) => {
            throw reason;
          };

    this.thenPromise = new MyPromise((resolve, reject) => {
      const resolvePromise = (cb: any) => {
        setTimeout(() => {
          try {
            const x = cb(this.PromiseResult);
            if (x === this.thenPromise) {
              throw new Error("不能返回自身");
            }
            if (x instanceof MyPromise) {
              x.then(resolve, reject);
            } else {
              resolve(x);
            }
          } catch (error: any) {
            reject(error);
          }
        });
      };
      if (this.PromiseStatus === "fulfilled") {
        resolvePromise(onFulfilled);
      } else if (this.PromiseStatus === "rejected") {
        resolvePromise(onRejected);
      } else {
        //暂时保存两个回调
        this.onFulfilledCallbacks.push(onFulfilled);
        this.onRejectedCallbacks.push(onRejected);
      }
    });

    return this.thenPromise;
  }

  static all(promises: MyPromise[]) {
    const result: Array<any> = [];
    let count = 0;
    return new MyPromise((resolve, reject) => {
      const addData = (index: number, data: any) => {
        result[index] = data;
        count++;
        if (count === promises.length) {
          resolve(result);
        }
      };
      promises.forEach((promise, index) => {
        if (promise instanceof MyPromise) {
          promise.then(
            (data) => addData(index, data),
            (err) => reject(err)
          );
        } else {
          addData(index, promise);
        }
      });
    });
  }

  static race(promises: MyPromise[]) {
    return new MyPromise((resolve, reject) => {
      promises.forEach((promise) => {
        if (promise instanceof MyPromise) {
          promise.then(
            (data) => resolve(data),
            (err) => reject(err)
          );
        } else {
          resolve(promise);
        }
      });
    });
  }
}

const test1 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve(100);
  }, 5000);
});

const test2 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve(200);
  }, 7000);
});
console.log("宏任务");

// MyPromise.all([test1, test2]).then((res) => console.log(res));
MyPromise.race([test1, test2]).then((res) => console.log(res));

function deepClone(obj: any, map = new Map()) {
  if (typeof obj !== "object") return obj;
  const temp: { [key: string]: any } | any[] = Array.isArray(obj) ? [] : {};
  if (map.get(obj)) return map.get(obj);
  map.set(obj, temp);

  for (let key in obj) {
    (temp as { [key: string]: any })[key] = deepClone(obj[key]);
  }
  return temp;
}

const demo2 = [
  {
    name: "张三",
  },
  {
    name: "李四",
  },
];
console.log(deepClone(demo2));

const Sleep = (time: number) =>
  new Promise((resolve) => setTimeout(resolve, time));

//用Promise包装一组数据返回
const getData = () =>
  new Promise((resolve) => {
    setTimeout(() => {
      resolve([
        {
          name: "张三",
          age: 15,
        },
      ]);
    }, 200);
  });
